package com.example.demo.udp;


import cn.hutool.json.JSONUtil;
import com.example.demo.config.ZuWangWebSocket;
import com.example.demo.controller.ConfigFileUtil;
import com.example.demo.controller.ZuWangController;
import com.example.demo.mapper.DataMonitorMapper;
import com.example.demo.mapper.DeviceMapper;
import com.example.demo.mapper.ExcelMapper;
import com.example.demo.pojo.BaseBean;
import com.example.demo.pojo.zuwang.datamonitor.DataMonitorStateBean;
import com.example.demo.pojo.zuwang.zuwang.Device;
import com.example.demo.pojo.zuwang.zuwang.ZuWangFromJSRes;
import com.example.demo.pojo.zuwang.zuwang.ZuWangReq;
import com.example.demo.util.CheckDeviceState;
import com.example.demo.util.DeviceStateEnum;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.socket.DatagramPacket;
import io.netty.util.concurrent.DefaultThreadFactory;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;


/**
 * @Description: UDP Netty 服务端事务处理器
 * @Author: junqiang.lu
 * @Date: 2023/8/25
 */
@Slf4j
@Component
@ChannelHandler.Sharable
public class DemoUdpNettyServerHandler extends SimpleChannelInboundHandler<DatagramPacket> {

    @Autowired
    public ZuWangWebSocket webSocket;

    @Autowired
    public ConfigFileUtil configFileUtil;

    @Autowired
    public DataMonitorMapper dataMonitorMapper;

    @Autowired
    public DeviceMapper deviceMapper;
    @Autowired
    public ExcelMapper excelMapper;

    @Autowired
    private ZuWangController zuWangController;

    public static DatagramPacket datagramPacket;
    public static Map<String, BaseBean> senderMap = new HashMap<>();
    /**
     * 工作线程池
     */
    private final ExecutorService executorService = new ThreadPoolExecutor(4, 8, 60, TimeUnit.SECONDS,
            new LinkedBlockingQueue<>(10000), new DefaultThreadFactory("UDP-netty-work-pool"),
            new ThreadPoolExecutor.CallerRunsPolicy());

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, DatagramPacket packet) {

        ByteBuf byteBuf = packet.content();
        byte[] bytes = new byte[byteBuf.readableBytes()];
        byteBuf.readBytes(bytes);
        // 异步处理业务
        executorService.execute(() -> {
            String body = new String(bytes, StandardCharsets.UTF_8);            // 读取数据
            log.info("UDP server receive client msg:" + body);

            BaseBean bean = JSONUtil.toBean(body, BaseBean.class);



            //组网的请求
            if (bean.getTranstype().equals("1000")) {
                ZuWangReq zuWangReq = JSONUtil.toBean(body, ZuWangReq.class);
                //判断这个设备是不是已经有了，有了的话则不推送给前端
                List<Device> resultBeans = deviceMapper.select();
                List<String> collect = resultBeans.stream().map(Device::getDevice).collect(Collectors.toList());
                if (!collect.contains(zuWangReq.getDevice())) {
                    //存入txt
                    zuWangReq.setUni(zuWangReq.getUni());
                    zuWangController.save(zuWangReq);
                    zuWangReq.setUniStr(String.valueOf(UUID.randomUUID()));
                    sendInfo(zuWangReq);
                }

            }//组网的应答(请求是集成通过postman  ZuWangBeanReq 请求接收机
            else if (bean.getTranstype().equals("1002")) {


                ZuWangFromJSRes zuWangFromJSRes = JSONUtil.toBean(body, ZuWangFromJSRes.class);
                handleDeviceFromHaveZuwang(zuWangFromJSRes);


            }

            //来消息之后，得判断数据库有没有，有了再存到map里
            Device device = deviceMapper.selectByUniIp(bean.getDevice() + bean.getSn() + bean.getIp());
            if (device != null) {
                senderMap.put(bean.getDevice(), bean);
            }

        });
    }

    private void handleDeviceFromHaveZuwang(ZuWangFromJSRes zuWangFromJSRes) {

        Device unZuwangDevice = deviceMapper.selectByUni(zuWangFromJSRes.getUni());
        //设备已存在
        if (unZuwangDevice != null) {
            //新设备新ip
            if (unZuwangDevice.getState().equals(DeviceStateEnum.UN_ZUWANG.getType())) {
                zuWangFromJSRes.setZuWangReq(true);
            }
            CheckDeviceState.updateDeviceZuwang(deviceMapper,unZuwangDevice,zuWangFromJSRes);
        }
        //增加数据监控信息 给图表类展示
        //添加env
        ZuWangFromJSRes.Env env = new ZuWangFromJSRes.Env();
        env.setDevice(zuWangFromJSRes.getDevice());
        env.setIp(zuWangFromJSRes.getIp());
        env.setSn(zuWangFromJSRes.getSn());
        env.setDatetime(zuWangFromJSRes.getDatetime());
        zuWangFromJSRes.setEnv(env);

        String fileName = "";
        switch (env.getDevice()) {
            case "YIHP":
                fileName = configFileUtil.autoCheck_jicheng_loc;
                break;
            case "YSRP":
                fileName = configFileUtil.autoCheck_jieshou_loc;
                break;
            case "YIRC":
                fileName = configFileUtil.autoCheck_remote_loc;
                break;
        }

        ConfigFileUtil.saveFile(fileName, zuWangFromJSRes);
        zuWangFromJSRes.setUnistr(String.valueOf(UUID.randomUUID()));
        sendInfo(zuWangFromJSRes);

        //存储设备监控状态
        insertFirstState(zuWangFromJSRes);
    }

    private void insertFirstState(ZuWangFromJSRes zuWangFromJSRes) {
        LocalDateTime now = LocalDateTime.now();
        String day = now.getYear() + "-" + now.getMonthValue() + "-" + now.getDayOfMonth();
        int hour = now.getHour();
        int minute = now.getMinute(); //比如 25

        //时间信息
        DataMonitorStateBean dMBean = new DataMonitorStateBean();
        //设备唯一标识 + 天数 + 小时 是唯一标识
        dMBean.setId(String.valueOf(UUID.randomUUID()));
        dMBean.setDay(day);
        dMBean.setHour(hour);
        dMBean.setMinute(minute);

        //基本信息
        dMBean.setDevice(zuWangFromJSRes.getDevice());
        dMBean.setIp(zuWangFromJSRes.getIp());
        dMBean.setSn(zuWangFromJSRes.getSn());
        dMBean.setUni(zuWangFromJSRes.getUni());

        dataMonitorMapper.insert(dMBean);

    }

    private void sendInfo(Object bean) {
        try {
            webSocket.sendInfo(JSONUtil.toJsonStr(bean));
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }


    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        log.error("UDP server read message error", cause);
    }
}
